package com.chuangjiangx.member.basic.ddd.domain.service;

import com.chuangjiangx.commons.redis.RedisKeyManager;
import com.chuangjiangx.commons.wx.auth.WXAuthApiUtils;
import com.chuangjiangx.commons.wx.auth.model.ApiAuthorizerTokenResp;
import com.chuangjiangx.commons.wx.jssdk.WXJssdkUtils;
import com.chuangjiangx.commons.wx.msg.WXMsgApiUtils;
import com.chuangjiangx.commons.wx.qrcode.CreateQrcodeReq;
import com.chuangjiangx.commons.wx.qrcode.CreateQrcodeResp;
import com.chuangjiangx.commons.wx.qrcode.WXQrcodeUtils;
import com.chuangjiangx.member.basic.ddd.domain.model.msg.WXMsg;
import com.chuangjiangx.member.basic.ddd.dal.mapper.WXPublicUserInfoDalMapper;
import com.chuangjiangx.member.basic.ddd.dal.mapper.WXisvDalMapper;
import com.chuangjiangx.member.basic.ddd.dal.dto.AgentWXPublicUserInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;


/**
 * @author cj-ch
 * @date 2018/1/2 下午6:06
 */
@Slf4j
@Service
public class MemberRedisDomainService {
    private static final Object LOCK = new Object();
    private static final Object QRCODE_LOCK = new Object();
    private static final Object JSSDK_LOCK = new Object();
    private static final Object JSCARDSDK_LOCK = new Object();
//    /**
//     * 商户的
//     */
//    public static final String REDIS_MERCHANT_ACCESS_TOKEN_SUFFIX = "_merchant_access_token";
//    /**
//     * 商户的jsapi_ticket
//     */
//    public static final String REDIS_MERCHANT_JSAPI_TICKET_SUFFIX = "_merchant_jsapi_ticket";
//    public static final String REDIS_MERCHANT_QRCODE_SUFFIX = "_merchant_qrcode";


//    public static final String REDIS_WXISV_ACCESS_TOKEN_SUFFIX = "_wxisv_access_token";
//    /**
//     * jsapi_ticket
//     */
//    public static final String REDIS_WXISV_JSAPI_TICKET_SUFFIX = "_wxisv_jsapi_ticket";
//    /**
//     * 客户公众号的二维码的key的后缀
//     */
//    public static final String REDIS_WXISV_QRCODE_SUFFIX = "_wxisv_qrcode";

    public static final String WX_MSG_TABLE_PREFIX = "WX_MSGID_TABLE_";
    @Value("${wx.public.appId}")
    private  String component_appid;

    public  String getComponent_appid() {
        return component_appid;
    }

    @Autowired
    private WXPublicUserInfoDalMapper wxPublicUserInfoDalMapper;
    @Autowired
    private WXisvDalMapper wXisvDalMapper;
    @Autowired
    private  StringRedisTemplate redisTemplate;

    public String getKeyValue(String key){
        return redisTemplate.opsForValue().get(key);
    }
    public String getKeyValueAndSet(String key,String value){
        return redisTemplate.opsForValue().getAndSet(key,value);
    }
    public String getKeyValueAndDel(String key){

        String s = redisTemplate.opsForValue().get(key);
        redisTemplate.delete(key);
        return s;
    }
    public void setKeyValue(String key,String value){
        setKeyValue(key,value,null,null);
    }

    public Boolean setIfAbsent(String key,String value){
        return redisTemplate.opsForValue().setIfAbsent(key,value);
    }
    public void delKey(String key){
        redisTemplate.delete(key);
    }
    public void expire(String key,TimeUnit unit,Long timeout){
        redisTemplate.expire(key,timeout,unit);
    }
    public void setKeyValue(String key,String value,TimeUnit unit,Long timeout){
        ValueOperations<String, String> forValue = redisTemplate.opsForValue();
        if(unit != null && timeout!=null){
            forValue.set(key,value,timeout,unit);
        } else {
            forValue.set(key,value);
        }

    }

    public Object getHashValue(String key,String field){
        return redisTemplate.opsForHash()
                .get(key,field);
    }

    public void setHashValue(String key,String field,Object value){
        redisTemplate.opsForHash()
                .put(key,field,value);
    }

    public boolean lock(String key,String value,long timeout,TimeUnit timeUnit){
        if(setIfAbsent(key,value)){
             redisTemplate.expire(key,timeout,timeUnit);
             return true;
         }
         return false;
    }



    /**
     * 获取微信第三方平台的component_access_token
     * @return
     */
    public String getComponent_access_token(){
        return (String) redisTemplate.opsForHash()
                .get("WXPublicId","componentAccessToken");
    }

    /**
     * 获取商户公众号的access_token
     * 基于微信第三方平台代商户公众号方式
     * @return
     */
    public String getMerchantAccessToken(Long merchantId){
        String commponentAccessToken = getComponent_access_token();
        String key = merchantId+RedisKeyManager.REDIS_MERCHANT_ACCESS_TOKEN_SUFFIX;
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        String accessToken = opsForValue.get(key);

        if(StringUtils.isBlank(accessToken)){
            synchronized (LOCK){
                accessToken = opsForValue.get(key);
                if(StringUtils.isBlank(accessToken)){
                    AgentWXPublicUserInfo agentWXPublicUserInfo = wxPublicUserInfoDalMapper.selectByMerchantId(merchantId);
                    if(agentWXPublicUserInfo == null){
//                        throw new BaseException("000001","获取商户公众号信息失败!");
                        return null;
                    }
                    //String component_appid, String component_access_token, String authorizer_appid, String authorizer_refresh_token
                    log.info("&&&调用微信API获取获取商户公众号access_token");
                    ApiAuthorizerTokenResp apiAuthorizerTokenResp = WXAuthApiUtils
                            .refreshAuthorizerTokenForComponent(
                                    component_appid,
                                    commponentAccessToken,
                                    agentWXPublicUserInfo.getAuthorizerAppid(),
                                    agentWXPublicUserInfo.getAuthorizerRefreshToken()
                            );
                    if(StringUtils.isBlank(apiAuthorizerTokenResp.getAuthorizer_access_token())){
//                        throw new BaseException("000001","获取商户公众号access_token失败");
                        return null;
                    }
                    accessToken = apiAuthorizerTokenResp.getAuthorizer_access_token();

                    opsForValue.set(key,accessToken
                            ,7000, TimeUnit.SECONDS);
                }
            }
        }
        return accessToken;
    }

    /**
     * 获取商户的jsticket
     * 基于微信第三方平台代商户公众号方式
     * @param merchantId
     * @return
     */
    public String getMerchantJsTicket(Long merchantId){
        String key = merchantId+RedisKeyManager.REDIS_MERCHANT_JSAPI_TICKET_SUFFIX;
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        String ticket = opsForValue.get(key);
        if(StringUtils.isBlank(ticket)){
            synchronized (JSSDK_LOCK){
                ticket = opsForValue.get(key);
                if(StringUtils.isBlank(ticket)){
                    String accessToken = getMerchantAccessToken(merchantId);
                    if(StringUtils.isBlank(accessToken)){
                        return null;
                    }
                    ticket = WXJssdkUtils.getTicket(accessToken);
                    if(StringUtils.isBlank(ticket)){
//                        throw new BaseException("000001","获取商户公众号JsTicket失败");
                        return null;
                    }
                    opsForValue.set(key,ticket
                            ,7000, TimeUnit.SECONDS);
                }
            }
        }
        return ticket;
    }

    /**
     * 获取商户的api-ticket（card专用）
     * 基于微信第三方平台代商户公众号方式
     * @param merchantId
     * @return
     */
    public String getMerchantJsCardTicket(Long merchantId){
        String key = merchantId+RedisKeyManager.REDIS_MERCHANT_API_TICKET_SUFFIX;
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        String ticket = opsForValue.get(key);
        if(StringUtils.isBlank(ticket)){
            synchronized (JSCARDSDK_LOCK){
                ticket = opsForValue.get(key);
                if(StringUtils.isBlank(ticket)){
                    String accessToken = getMerchantAccessToken(merchantId);
                    if(StringUtils.isBlank(accessToken)){
                        return null;
                    }
                    ticket = WXJssdkUtils.getCardApiTicket(accessToken);
                    if(StringUtils.isBlank(ticket)){
//                        throw new BaseException("000001","获取商户公众号JsTicket失败");
                        return null;
                    }
                    opsForValue.set(key,ticket
                            ,7000, TimeUnit.SECONDS);
                }
            }
        }
        return ticket;
    }

    /**
     * 获取微信模板消息ID
     * 基于微信第三方平台代商户公众号方式
     * @param merchantId
     * @param wxMsg
     * @return
     */
    public String getMerchantWxTemplateId( Long merchantId, WXMsg wxMsg) {
        String hashKey = WX_MSG_TABLE_PREFIX + merchantId;
        String field = wxMsg.number;
        String templateId = (String) getHashValue(hashKey, field);
        if(StringUtils.isBlank(templateId)){
            synchronized (LOCK){
                //获得锁后再次判断
                templateId = (String) getHashValue(hashKey, field);
                if(StringUtils.isBlank(templateId)){
                    String accessToken = getMerchantAccessToken(merchantId);
                    //调用微信接口
                    templateId = WXMsgApiUtils.getTemplateId(accessToken, wxMsg.number, wxMsg.title);
                    if(StringUtils.isNotBlank(templateId)){
                        //获取成功后存储到redis
                        setHashValue(hashKey,field,templateId);
                    }
                }
            }
        }
        return templateId;
    }

    /**
     * 获取商户公众号的二维码
     * 基于微信第三方平台代商户公众号方式
     * @param merchantId
     * @return
     */
    public String getMerchantWxQrcodeUrl(Long merchantId){

        String key = merchantId + RedisKeyManager.REDIS_MERCHANT_QRCODE_SUFFIX;
        ValueOperations<String, String> redis = redisTemplate.opsForValue();
        String qrcodeUrl = redis.get(key);
        if(StringUtils.isBlank(qrcodeUrl)){
            synchronized (QRCODE_LOCK){
                qrcodeUrl = redis.get(key);
                if(StringUtils.isBlank(qrcodeUrl)){
                    //二次判断后还是空的
                    String access_token = getMerchantAccessToken(merchantId);
                    if(StringUtils.isNotBlank(access_token)){
                        //有效期20天
                        Long validity = 60*60*24*20L;
                        CreateQrcodeReq createQrcodeReq = new CreateQrcodeReq(
                                validity,
                                //临时的整型参数值
                                CreateQrcodeReq.ActionName.QR_SCENE,
                                0L
                        );
                        CreateQrcodeResp qrcode = WXQrcodeUtils.createQrcode(access_token, createQrcodeReq);
                        qrcodeUrl = qrcode.getUrl();
                        if(StringUtils.isNotBlank(qrcodeUrl)){
                            //储值到redis并且设置有效期
                            redis.set(key,qrcodeUrl,
                                    validity-3600L,TimeUnit.SECONDS);
                        }
                    }
                }
            }
        }
        return qrcodeUrl;
    }



//    /**
//     * 根据商户获取商户签约的服务商的公众号的access_token
//     * 定时任务负责刷新
//     * @param merchantId
//     * @return
//     */
//    public String getWxisvAccessToken(Long merchantId){
//        WXisv wXisv = wXisvDalMapper.selectByMerchantId(merchantId);
//        if(wXisv == null){
//            return null;
//        }
//        return getWxisvAccessToken2(wXisv.getId());
//    }
//
//    public String getWxisvAccessToken2(Long wxisvId){
//
//        String key = wxisvId + REDIS_WXISV_ACCESS_TOKEN_SUFFIX;
//        return redisTemplate.opsForValue()
//                .get(key);
//    }
//
//    /**
//     * 根据商户获取商户签约的服务商的公众号的JsTicket
//     * 定时任务负责刷新
//     * @param merchantId
//     * @return
//     */
//    public String getWxisvJsTicket(Long merchantId){
//        WXisv wXisv = wXisvDalMapper.selectByMerchantId(merchantId);
//        if(wXisv == null){
//            return null;
//        }
//        String key = wXisv.getId() + REDIS_WXISV_JSAPI_TICKET_SUFFIX;
//        return redisTemplate.opsForValue()
//                .get(key);
//    }
//
//    /**
//     * 获取微信模板消息ID
//     * @param merchantId
//     * @param wxMsg
//     * @return
//     */
//    public String getWxisvMsgTemplateId( Long merchantId, WXMsg wxMsg) {
//        WXisv wXisv = wXisvDalMapper.selectByMerchantId(merchantId);
//        if(wXisv == null){
//            return null;
//        }
//        String hashKey = WX_MSG_TABLE_PREFIX + wXisv.getId();
//        String field = wxMsg.number;
//        String templateId = (String) getHashValue(hashKey, field);
//        if(MbrStringUtils.isBlank(templateId)){
//            synchronized (LOCK){
//                /**
//                 * 为了避免死锁这里不可以调用 {@link MemberRedisDomainService#getWxisvQrcodeUrl(Long)} 方法
//                 */
//                //获得锁后再次判断
//                templateId = (String) getHashValue(hashKey, field);
//                if(MbrStringUtils.isBlank(templateId)){
//                    String accessToken = getWxisvAccessToken(merchantId);
//                    //调用微信接口
//                    templateId = WXMsgApiUtils.getTemplateId(accessToken, wxMsg.number, wxMsg.title);
//                    if(MbrStringUtils.isNotBlank(templateId)){
//                        //获取成功后存储到redis
//                        setHashValue(hashKey,field,templateId);
//                    }
//                }
//            }
//        }
//        return templateId;
//    }

//    /**
//     * 获取服务商公众号的二维码
//     * @param merchantId
//     * @return
//     */
//    public String getWxisvQrcodeUrl(Long merchantId){
//        WXisv wXisv = wXisvDalMapper.selectByMerchantId(merchantId);
//        if(wXisv == null){
//            return null;
//        }
//        String key = wXisv.getId() + REDIS_WXISV_QRCODE_SUFFIX;
//        ValueOperations<String, String> redis = redisTemplate.opsForValue();
//        String qrcodeUrl = redis.get(key);
//        if(MbrStringUtils.isBlank(qrcodeUrl)){
//            synchronized (QRCODE_LOCK){
//                qrcodeUrl = redis.get(key);
//                if(MbrStringUtils.isBlank(qrcodeUrl)){
//                    //二次判断后还是空的
//                    String access_token = getWxisvAccessToken2(wXisv.getId());
//                    if(MbrStringUtils.isNotBlank(access_token)){
//                        //有效期20天
//                        Long validity = 60*60*24*20L;
//                        CreateQrcodeReq createQrcodeReq = new CreateQrcodeReq(
//                                validity,
//                                //临时的整型参数值
//                                CreateQrcodeReq.ActionName.QR_SCENE,
//                                0L
//                        );
//                        CreateQrcodeResp qrcode = WXQrcodeUtils.createQrcode(access_token, createQrcodeReq);
//                        qrcodeUrl = qrcode.getUrl();
//                        if(MbrStringUtils.isNotBlank(qrcodeUrl)){
//                            //储值到redis并且设置有效期
//                            redis.set(key,qrcodeUrl,
//                                    validity-3600L,TimeUnit.SECONDS);
//                        }
//                    }
//                }
//            }
//        }
//        return qrcodeUrl;
//    }

    /**
     * 检查商户是否开通了会员功能
     * @param merchantId
     * @return
     */
    public boolean merchantOpenedMember(Long merchantId){
        String key = merchantId + "-13";
        Object value = redisTemplate.boundHashOps(RedisKeyManager.MERCHANT_USE_PRODUCT_HASH)
                .get(key);
        return value != null;
    }
}
